/**
 * @file quic_svd.hpp
 * @author Mudit Raj Gupta
 *
 * Defines the QUIC SVD class for Matrix Factorization
 * on a given sparcely populated matrix.
 */
#ifndef __MLPACK_CORE_OPTIMIZERS_QUIC_SVD_QUIC_SVD_HPP
#define __MLPACK_CORE_OPTIMIZERS_QUIC_SVD_QUIC_SVD_HPP

#include <mlpack/core.hpp>
#include "../cosine_tree/cosine_tree.hpp"
#include "../cosine_tree/cosine_tree_builder.hpp"

namespace mlpack {
namespace quicsvd {

class QuicSVD
{
 private:
  //! Epsilon Value
  double epsilon;
  //! Error Range
  double delta;
  //! Maximum Number of Iteratiosn
  size_t maxIterations;

  /**
   * Length Square Sampling method for sampling rows
   * of the matrix
   *
   * @param A Matrix for which probabilities are calculated
   * @param prob Reference to the probability vector
   */
  void LSSampling(arma::mat Q, arma::vec& probabilities); 

   /**
   * Return the Euclidean Norm of the vectoe
   * 
   * @param A Vector for which Euclidean Norm has to be calculated
   */
  double EuclideanNorm(arma::vec A);

  /** 
   * Calculates Modified Gram-Schmidt orthonormalization
   * 
   * @param V Initial Matrix
   * @param VNorm Normalazied Matrix
   */
  arma::mat MGS(arma::mat V);
  
  /**
   * Approximate SVD
   *
   * @param U U Matrix after decomposition 
   * @param sigma sigma matrix after decomposition
   * @param V V Matrix after decomposition
   * @param A Origional Matrix
   * @param VCap Orthogonal Basis
   */
  void ExtractSVD(arma::mat& U, arma::mat& sigma, arma::mat& V, arma::mat A, arma::mat VCap);
  
  /**
   * Generates row samples based on sampling algorithm
   *
   * @param A Matrix with all the points
   * @param S Sampled Matrix
   * @param ps Probability for the sampled matrix coloums
   * @param n Size of the sample space
   */
  void RowSamplesLS(arma::mat A, arma::mat& S, arma::vec& ps, size_t n)
  
  /**
   * Calculates the lower bound
   * 
   * @param mu Mean
   * @param variance Variance
   * @param s Sample Size
   */
  double LowBound(double mu, double variance, size_t s);

  /**   
   * Calculates the  Monte-Carlo Square Error
   *
   * @param A Matrix with all the points
   * @param V Orthogonal Subspace
   * @param n Size of the sample space
   */ 
  double MCSqError(arma::mat A, arma::mat V, size_t n);

 public:
  //! Constructor
  QuicSVD(double epsilon, double delta, double maxIterations);
  //! Empty Constructor
  QuicSVD();
  //! Setter for Epsilon
  void Epsilon(double e);
  //! Getter for Epsilon
  double Epsilon();
  //! Setter for Delta
  void Delta(double d);
  //! Getter for Delta
  double Delta();
  //! Setter for Maximum Number of Iterations
  void MaxIterations(size_t m);
  //! Getter for Maximum Number of Iterations
  size_t MaxIterations();
  //! Applies Quic SVD 
  void Apply(arma::mat& U, arma::mat& sigma, arma::mat& V, arma::mat A);

}; // class QUIC_SVD

}; // namespace quicsvd
}; // namespace mlpack

// Include implementation.
#include "quic_svd_impl.hpp"

#endif
